#ifndef XG_REFLECT_H
#define XG_REFLECT_H
//////////////////////////////////////////////////////////////////////////////
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <ctime>
#include <mutex>
#include <atomic>
#include <vector>
#include <string>
#include <cctype>
#include <cstdio>
#include <cstdarg>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <memory>
#include <iostream>
#include <typeinfo>

#define reflect_object(type, name)			\
type name;									\
ReflectHelper __##name = ReflectHelper(this, &this->name, #type, #name)

#define reflect_attr(type, name, defval)	\
type name = defval;							\
ReflectHelper __##name = ReflectHelper(this, &this->name, #type, #name)

#define rint(name) reflect_attr(int, name, 0)
#define rbool(name) reflect_attr(bool, name, false)
#define rfloat(name) reflect_attr(float, name, 0.0F)
#define rdouble(name) reflect_attr(double, name, 0.0F)

#define reflect_int(name) reflect_attr(int, name, 0)
#define reflect_bool(name) reflect_attr(bool, name, false)
#define reflect_float(name) reflect_attr(float, name, 0.0F)
#define reflect_double(name) reflect_attr(double, name, 0.0F)

#define rstring(name) reflect_object(string, name)
#define robject(type, name) reflect_object(type, name)
#define reflect_string(name) reflect_object(string, name)

#define sp shared_ptr
#define newsp make_shared
#define ARR_LEN(arr) (sizeof(arr)/sizeof(arr[0]))
#define CHECK_FALSE_RETURN(FUNC) if (FUNC){} else return false

#ifdef _MSC_VER
#define strcasecmp stricmp
#pragma warning(disable:4996)
#endif

using namespace std;

typedef unsigned long long ReflectKey;

class Object
{
public:
	virtual ~Object();
	virtual string toString() const;
	virtual const char* getClassName() const;
};

class SpinMutex : public Object
{
private:
	atomic_flag flag = ATOMIC_FLAG_INIT;

public:
	void lock()
	{
		while (flag.test_and_set(memory_order_acquire));
	}
	void unlock()
	{
		flag.clear(std::memory_order_release);
	}
};

typedef lock_guard<SpinMutex> SpinLocker;

class ReflectItem
{
	friend class JsonReflect;

protected:
	int offset;
	const char* name;
	const char* type;

public:
	ReflectItem() : offset(0), type(NULL)
	{
	}
	ReflectItem(int _offset, const char* _type, const char* _name) : offset(_offset), type(_type), name(_name)
	{
	}

public:
	bool operator < (const ReflectItem& obj) const
	{
		return offset < obj.offset;
	}
	bool operator == (const ReflectItem& obj) const
	{
		return offset == obj.offset;
	}

public:
	string get(const void* obj) const;
	bool set(void* obj, int val) const;
	bool set(void* obj, double val) const;
	bool set(void* obj, const char* val) const;

	bool canUse() const
	{
		return type ? true : false;
	}
	int getOffset() const
	{
		return offset;
	}
	const char* getName() const
	{
		return name;
	}
	const char* getType() const
	{
		return type;
	}
	bool set(void* obj, bool val) const
	{
		return set(obj, val ? 1 : 0);
	}
	bool set(void* obj, float val) const
	{
		return set(obj, (double)(val));
	}
	bool set(void* obj, const string& val) const
	{
		return set(obj, val.c_str());
	}
};

class ReflectHelper
{
public:
	static string GetAttrString(ReflectKey key);
	static vector<ReflectItem> GetAttrList(ReflectKey key);
	ReflectHelper(Object* self, void* data, const char* type, const char* name);
	ReflectHelper(Object* self, Object* data, const char* type, const char* name);

	static ReflectKey GetKey(const Object* obj)
	{
		return (ReflectKey)(typeid(*obj).name());
	}
	template<class REFLECT_TYPE> static ReflectKey GetKey()
	{
		return (ReflectKey)(typeid(REFLECT_TYPE).name());
	}

	static string GetAttrString(const Object* obj)
	{
		return GetAttrString(GetKey(obj));
	}
	template<class REFLECT_TYPE> static string GetAttrString()
	{
		string res = GetAttrString(GetKey<REFLECT_TYPE>());

		if (res.length() > 0) return res;

		REFLECT_TYPE item;

		return GetAttrString(&item);
	}


	static vector<ReflectItem> GetAttrList(const Object* obj)
	{
		return GetAttrList(GetKey(obj));
	}
	template<class REFLECT_TYPE> static vector<ReflectItem> GetAttrList()
	{
		vector<ReflectItem> vec = GetAttrList(GetKey<REFLECT_TYPE>());

		if (vec.size() > 0) return std::move(vec);

		REFLECT_TYPE item;

		return GetAttrList(&item);
	}
};
//////////////////////////////////////////////////////////////////////////////
#endif
